{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adversarial Training\n",
    "\n",
    "This notebook shows the creation of an adversarial training methodology to harden a neural network against a digital FGSM attack.\n",
    "\n",
    "### Assumptions\n",
    "- The dataset wrangling has already been completed (and is provided here)\n",
    "- The adversarial attack (FGSM) has already been completed\n",
    "- The outer loop of training has already been completed and we're only subclassing a single epoch\n",
    "- The plotting code has already been completed\n",
    "\n",
    "### Components Recreated in Tutorial\n",
    "- Adversarial training constrained by a power ratio and a percentage of the dataset it alters each epoch.\n",
    "\n",
    "### See Also\n",
    "The code in this tutorial is a stripped down version of the code in ``rfml.nn.train.adversarial`` that simplifies discussion.  Further detail can be provided by directly browsing the source files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Install the library code\n",
    "#!pip install git+https://github.com/brysef/rfml.git@1.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "setGPU: Setting GPU to: 0\n"
     ]
    }
   ],
   "source": [
    "# Ensure that the least loaded GPU is used\n",
    "import setGPU\n",
    "\n",
    "# Plotting Includes\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# External Includes\n",
    "import numpy as np\n",
    "\n",
    "import torch\n",
    "from torch.autograd import Variable\n",
    "from torch.nn import CrossEntropyLoss\n",
    "from torch.optim import Adam\n",
    "from torch.utils.data import DataLoader, TensorDataset\n",
    "\n",
    "# Internal Includes\n",
    "from rfml.attack import fgsm\n",
    "\n",
    "from rfml.data import Dataset, Encoder\n",
    "from rfml.data import build_dataset\n",
    "\n",
    "from rfml.nbutils import plot_acc_vs_spr, plot_acc_vs_snr\n",
    "\n",
    "from rfml.nn.eval import compute_accuracy, compute_accuracy_on_cross_sections\n",
    "from rfml.nn.model import build_model, Model\n",
    "from rfml.nn.train import StandardTrainingStrategy, PrintingTrainingListener"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Configuration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "gpu = True       # Set to True to use a GPU for training\n",
    "fig_dir = None   # Set to a file path if you'd like to save the plots generated\n",
    "data_path = None # Set to a file path if you've downloaded RML2016.10A locally"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adversarial Training of a Model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load dataset and a DNN model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "train, val, test, le = build_dataset(\"RML2016.10a\", path=data_path)\n",
    "# as_numpy returns x,y and x is shape BxCxIQxN\n",
    "input_samples = val.as_numpy(le=le)[0].shape[3]\n",
    "model = build_model(model_name=\"CNN\", input_samples=input_samples, n_classes=len(le))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Creating our own adversarial trainer\n",
    "\n",
    "One of the most effective, and simple, methodologies for hardening deep learning models against adversarial attacks is simply \"showing\" them what they are.  A process known as adversarial training.\n",
    "\n",
    "Here, we recreate the adversarial training from [Kurakin et al.] that uses the FGSM attack from [Goodfellow et al.] to augment the training examples with adversarial examples.  Note that this coupling of adversarial attack and training was found, in the context of computer vision, to produce robustness which was misleading because it was actually learning to obfuscate the gradient used as a \"signal\" to create the adversarial example and not necessarily becoming robust to the attack [Tramer et al.].  The adversarial training methodology was then extended to Ensemble Adversarial Training by [Tramer et al.], however, this notebook only demonstrates the adversarial training proposed in [Kurakin et al.] as it can be more easily self-contained into a notebook for demonstration.\n",
    "\n",
    "Also note that adversarial training was applied in the context of RF in [Kokalj-Filipovic and Miller].\n",
    "\n",
    "#### Goodfellow et al.\n",
    "Goodfellow, I., Shlens, J., and Szegedy, C. (2015). Explaining and harnessing adversarial examples. In Int. Conf. on Learning Representations.\n",
    "\n",
    "#### Kurakin et al.\n",
    "\n",
    "Kurakin, A., Goodfellow, I. J., and Bengio, S. (2016).  Adversarial machine learning at scale.CoRR, abs/1611.01236.\n",
    "\n",
    "#### Tramer et. al\n",
    "Tramer, F., Kurakin, A., Papernot, N., Boneh, D., and McDaniel, P. D. (2017). Ensemble adversarial training: Attacks and defenses.CoRR, abs/1705.07204.\n",
    "\n",
    "#### Kokalj-Filipovic and Miller\n",
    "\n",
    "Kokalj-Filipovic, S. and Miller, R. (2019). Adversarial examples in RF deep learning: Detection of the attack and its physical robustness.CoRR, abs/1902.06044."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyAdversarialTrainingStrategy(StandardTrainingStrategy):\n",
    "\n",
    "    def __init__(\n",
    "        self,\n",
    "        lr: float = 10e-4,\n",
    "        max_epochs: int = 50,\n",
    "        patience: int = 5,\n",
    "        batch_size: int = 512,\n",
    "        gpu: bool = True,\n",
    "        k: float = 0.05,\n",
    "        spr: float = 10.0,\n",
    "    ):\n",
    "        super().__init__(\n",
    "            lr=lr,\n",
    "            max_epochs=max_epochs,\n",
    "            patience=patience,\n",
    "            batch_size=batch_size,\n",
    "            gpu=gpu,\n",
    "        )\n",
    "        self.k = k\n",
    "        self.spr = spr\n",
    "\n",
    "        # The exact value of the sps shouldn't actually matter.  It's simply used for\n",
    "        # an intermediate scaling of the example before applying the adversarial\n",
    "        # perturbation with FGSM.  This assumption that it shouldn't matter is based\n",
    "        # upon the expectation the model does the normalization as the first \"layer\"\n",
    "        # in its network.\n",
    "        self.sps = 8\n",
    "\n",
    "    def _train_one_epoch(\n",
    "        self, model: Model, data: DataLoader, loss_fn: CrossEntropyLoss, optimizer: Adam\n",
    "    ) -> float:\n",
    "        total_loss = 0.0\n",
    "        # Switch the model mode so it remembers gradients, induces dropout, etc.\n",
    "        model.train()\n",
    "\n",
    "        for i, batch in enumerate(data):\n",
    "            x, y = batch\n",
    "\n",
    "            # Perform adversarial augmentation in the training loop using FGSM\n",
    "            x = self._adversarial_augmentation(x=x, y=y, model=model)\n",
    "\n",
    "            # Push data to GPU\n",
    "            if self.gpu:\n",
    "                x = Variable(x.cuda())\n",
    "                y = Variable(y.cuda())\n",
    "            else:\n",
    "                x = Variable(x)\n",
    "                y = Variable(y)\n",
    "\n",
    "            # Forward pass of prediction -- while some are adversarial\n",
    "            outputs = model(x)\n",
    "\n",
    "            # Zero out the parameter gradients, because they are cumulative,\n",
    "            # compute loss, compute gradients (backward), update weights\n",
    "            loss = loss_fn(outputs, y)\n",
    "            optimizer.zero_grad()\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "\n",
    "            total_loss += loss.item()\n",
    "\n",
    "        mean_loss = total_loss / (i + 1.0)\n",
    "        return mean_loss\n",
    "\n",
    "    def _adversarial_augmentation(\n",
    "        self, x: torch.Tensor, y: torch.Tensor, model: Model\n",
    "    ) -> torch.Tensor:\n",
    "        # Rely on the fact that the DataLoader shuffles -- therefore can just take the\n",
    "        # first *n* examples and perform adversarial augmentation on it and it will be\n",
    "        # a random selection.\n",
    "        n_adversarial = int(self.k * x.shape[0])\n",
    "        if n_adversarial == 0:\n",
    "            return x\n",
    "\n",
    "        x[0:n_adversarial, ::] = fgsm(\n",
    "            x=x[0:n_adversarial, ::],\n",
    "            y=y[0:n_adversarial],\n",
    "            net=model,\n",
    "            spr=self.spr,\n",
    "            sps=self.sps,\n",
    "        )\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 0 completed!\n",
      "\t\t-Mean Training Loss: 1.566\n",
      "\t\t-Mean Validation Loss: 1.263\n",
      "Epoch 1 completed!\n",
      "\t\t-Mean Training Loss: 1.316\n",
      "\t\t-Mean Validation Loss: 1.209\n",
      "Epoch 2 completed!\n",
      "\t\t-Mean Training Loss: 1.224\n",
      "\t\t-Mean Validation Loss: 1.204\n",
      "Epoch 3 completed!\n",
      "\t\t-Mean Training Loss: 1.129\n",
      "\t\t-Mean Validation Loss: 1.195\n",
      "Epoch 4 completed!\n",
      "\t\t-Mean Training Loss: 1.066\n",
      "\t\t-Mean Validation Loss: 1.202\n",
      "Epoch 5 completed!\n",
      "\t\t-Mean Training Loss: 1.020\n",
      "\t\t-Mean Validation Loss: 1.251\n",
      "Epoch 6 completed!\n",
      "\t\t-Mean Training Loss: 0.977\n",
      "\t\t-Mean Validation Loss: 1.294\n",
      "Training has Completed:\n",
      "\n",
      "=======================\n",
      "\tBest Validation Loss: 1.195\n",
      "\tBest Epoch: 3\n",
      "\tTotal Epochs: 6\n",
      "=======================\n"
     ]
    }
   ],
   "source": [
    "trainer = MyAdversarialTrainingStrategy(max_epochs=10,\n",
    "                                        patience=3,\n",
    "                                        gpu=gpu,\n",
    "                                        k=0.25,\n",
    "                                        spr=10)\n",
    "trainer.register_listener(PrintingTrainingListener())\n",
    "trainer(model=model, training=train, validation=val, le=le)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Testing the Adversarial Trained Model on normal data\n",
    "This ensures that we haven't completely sacraficed our performance in the baseline case."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overall Testing Accuracy: 0.5892\n"
     ]
    }
   ],
   "source": [
    "acc = compute_accuracy(model=model, data=test, le=le)\n",
    "print(\"Overall Testing Accuracy: {:.4f}\".format(acc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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6647rm3Onz+fDRs25Ey/+uqr/PTTT6USL8Czzz7LBRdcQHb2iQ2QGChr1qzJua1HYmIid955J4MGDeKyyy7LueVPbGws1157LZdddhkDBw5k7tzci5C9txd55ZVXcuZNnjyZ+fPn50wvWrSIV1999SQdUcWWkp7Fm99vpMcLi3htwXp6tKnFm4Ma8esjfXj372fxYF9Dv471aVwjqtwkYyJSdvgtIbPWZgIjgW+AWJyrKVcbY542xgxyV3sAuM0Y8xfwCTDMWlvmbx0QERHBjBkzmD17NqGhoXz66ad+29ejjz5KTEwM3377LdOnT2f8+PEcPHiw1Pdz/fXXM2TIEAAWLFhA3759+eqrr2jYsOFxH1/BhGzUqFF07969VOLNzs5m/vz51K9fP+dem/7g8Xj8lvC9+eab/O1vfwPgo48+omXLlsycOZMPPviACRMmkJ6eTkREBBMmTGDOnDm8/fbbjB8/noSEBNauXUtERASzZs1i5cqVJCYmsnfvXlasWEGfPrldMXv27MmiRYuO+0eDOJ2O31+6hR4vLuL5eWvp0rgas+85n8k3dqVp9fI1IKmIlF1+7RDjjik2t8C8x/M8XwOc588Y/K1bt25YawGYMWMGH3zwARkZGXTu3JknnniCkJAQnnjiCVauXElaWhp9+/bl3nvvzbeN1NRURo4cySWXXMI111yTM3/btm389ddfvPTSSwQHO7lz48aNady4cb7XJyUlMWLECBISEsjMzGTUqFH06dOH5ORkRo8eze7du8nOzmbEiBH079+fl156iYULFxISEsL555/PP//5T/71r38RFRVFq1atmDp1KsHBwSxdupRXXnmF008/nT///BOAKVOmMGvWLIKCgujRowcPPvgg06ZN47PPPiMjI4OmTZvywgsvEBsby8KFC/n111954403+Ne//sXkyZPp2bMn/fr1Y+nSpUyYMIGsrCw6duzIU089RVhYGL1792bIkCEsWrSIzMxMJk2aRMuWLY8q919++YVWrVrRv39/5syZwznnnJNTFuPGjWPVqlUAjBw5kr59+/LDDz8wceJEsrKyqF69OlOnTs055uHDhwPODXXffPNNAIYPH07nzp1ZvXo1U6ZMYcqUKfz5559kZWXlew9XrFjB+PHjSU5OJiwsjPfee4877riDRx99NKea/vrrr+eJJ56gbdu2OfEfOXIE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jx7NLbfcQnZ2NqGhoTz++ON06dKF9u3bc+mll1KvXj3OOOOMo177yCOPMHbsWF544QUeeuihfMueffZZnn/+eS6++GIiIiKoXr06//jHP/KtM3DgQO666y4GDhxIx44dadGiBQDr1q3jhRdeIDg4mEqVKvHkk0/mXADgreEZM2aMz8fYo0cP1q5dy5VXXkloaCgXXngh999/P6NGjeLqq6+mRo0adO7cOScJ69+/P4899hgffPABr732Ws52wsPDee655xg1alROp/7rr7/epxhSUlL48ccf8yWwUVFRdO3alUWLFnHXXXfx9NNPM2DAAIKDg3Mulnj66ae55557yM7OpmbNmrz77rv07duXGTNmcNlll9GpUyeaNWtW6D7btm1L+/btueGGG2jUqFHOexgWFsbEiRMZN25czuCH7777LpUqVaJjx45ER0cX2lwJ0LJlS44cOcKRI0eIjo5mxIgRPPzwwwwcOBCPx8ODDz5IjRo1mDFjBr///juHDh3iyy+/BOD555/PuWDgo48+4vLLLycyMhJjDKmpqQwcOJAePXpQtaozavsvv/zC/fff71P5nirW7k7g5W/X8d2aPdSoHMajl7XjpnOalsqo+SIix8NvI/X7S2xsrEcDw548FXUw1ONxLGWxZ88e/va3vzFv3ryjOud7vffee1SuXJmrr766NMPMJz4+ngceeICpU6eW6nbL6//IlvgkJs5fx8y/dhIdXonbL2jB389vflw33IbyWw7+oLLIpbLIpbKAZcuWBXykfpFT0ldffcXEiRMZM2ZMkckYOMNhzJs3z6+x7Ny585hqQSuqnYdS+NfC9Uz7fQdhIcHceWFL7ujRgmpRGkdMRMoGJWQipaywIUwKEx4e7tN6J8J7BeipKv5IGpMXbeTDX7aCB4ae05QRvVpSp8qpfW89ESl7lJCJSIVzODmDKT9u5N3/bSE1I4urujbi3ota06h6VMkvFhEJACVkIlJhpGZk8c7/NvPm4o0kpGYyoFN97ru4DS1rRwc6NBGRYikhE5EK4ft1+3hixiq27E/morZ1uP+SNnRocPSQIyIiZZESMimWd5BWUVmUVTsPpfDM7DXMW7WbFrUq88Hws7igta4MFpHyRQmZFGvXrl0+3WroVKCyKFvSM7N553+beW3BerI9Hv7R13DrBc0Jr6SxxESk/FFCJiLlzk8b43l8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\n",
      "text/plain": [
       "<Figure size 720x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "acc_vs_snr, snr = compute_accuracy_on_cross_sections(model=model,\n",
    "                                                     data=test,\n",
    "                                                     le=le,\n",
    "                                                     column=\"SNR\")\n",
    "\n",
    "title = \"Accuracy vs SNR of {model_name} on {dataset_name}\".format(model_name=\"CNN\", dataset_name=\"RML2016.10A\")\n",
    "fig = plot_acc_vs_snr(acc_vs_snr=acc_vs_snr, snr=snr, title=title)\n",
    "if fig_dir is not None:\n",
    "    file_path = \"{fig_dir}/hardened_acc_vs_snr.pdf\"\n",
    "    print(\"Saving Figure -> {file_path}\".format(file_path=file_path))\n",
    "    fig.savefig(file_path, format=\"pdf\", transparent=True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Verifying the Model has been Hardened\n",
    "Attempt Evading Signal Classification with Direct Access to the Classifier again to see if we have improved over our prior attack."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "mask = test.df[\"SNR\"] >= 18\n",
    "dl = DataLoader(test.as_torch(le=le, mask=mask), shuffle=True, batch_size=512)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmQAAAFRCAYAAADaTrE/AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzs3Xd4VFX+x/F3eiEBQui9H3ARaSq6FsSuBJCioLLqiq66CpbVH9h1dXV1rWtZXQuuii4idkEFFXVFgQgiEg4dEjqEkl7n98e9CZNCMsFMZpJ8Xs+TZ3Lntu+dc2fmO+ece26Ix+NBRERERAInNNABiIiIiDR2SshEREREAkwJmYiIiEiAKSETERERCTAlZCIiIiIBpoRMREREJMDCAx1AsDHGdAL+AwwFooEka+3HgY0quBljHgauBFoC71prx9XhvkvGbelmrd3kw/LDgK+Azdbarr9hv5cDrwILrbXDjnQ7UpE/XltjzNHuNvsDEcDR1tqVtbHtYGGMuRe4B/jAWju6lrf5mrX28trYpohUrl4mZMaYTUAXr6f2AsnAHdbapb9x89OBYcBKYAGw4Tdur0EzxhwH/B+QCzwPLK6l7W7CKWMPkA3scbf9mLX2R69Fn3IfD/q46TR3nXSvfdUoqfOV13bLS7DW7neX6QPcAZwGtAb2A2twvgD/7S7THfgHcBLQFOe1WAn82Vq73hjTFdjobvsA0MFam+WueyfwV3delV+qxpg4YCcQC+QBbUvidOd/DZwKXGGtneE+V7pva21I9a9KwPwdGAwswjmP9lR2PLXJ6xy+wFr7vvvcMJwfBAestc1re59+8APO+6VW3tcicnj1MiHz8jHOl8GpwFnAscaYPtbaXTXdkDEmwlpbAPR2n3rCWvvKkQbmtb2GruT1WmKtvc4P2/8E2A38HhgPXGCMudha+w6AtfbGmmzMWrsOqNE6tWAmzjGUyAMwxpwEfA7EAFuAt3BqbwYDfwL+7S7/Hk7Nzpc4yVpH4BSgHbC+3L6aAROBl4wxYcDVNYhzDE4yBhAFXAi8WIP1g1nJeXqntfZLAGNMrWy4rt/rdbk/a+08YF5d7EuksavvCdnL1tr3jTGJOLUGCcAJwAfGmH44v4qPBUKAb4CbrLVboEztxU3AVMBjjNmCk9wBvGyMeRnohvNlei/OF1YbYB1OTc3r7rbuxanWfxcoBpKAa93ag3twPtD2uuuvBC4GbnMfNwF/sNb+5G5rphtDSyAfWAJMtdb+4s7fhPOrezpwEc4XzULgEmvtPneZocD9wECcL/uVwHBrbXZ1r0t5xphWwEM4CW9zYBVwr7V2nlfTEsDJ7mt6n7X23nLbaAf8FzgKJ2HYD3wGXO9dA3MYJWUcDrwOTAD+ZYz5xD2eMrVbxpijgFdwEpivcGo4r8dtxinfZFmuFmuj+yV9Gk5i9AjQHSdJ2QbMsNbeU028lXnUWru8kuf/jVM+3wDnWmuzS2a4TWwYY1q4x7IfOMNa63GfjwLCKtnmPuBa4CXgfKCT+1yCD3Fe6j4uwzl3LsVNyLxqkwBeNca8CrwGXOYVc2lZ4NTm3e7uPwrnPH/SWvuc1/KTcJLj3kAB8I619k/lgzLGjAbewan9O91a+3O5+VWeX+Vq1Be4ZbywkuO5z1p7r5soPwAcA+TgvH9vtdbuLVcbeS1wN2BxzpkjUoP3/J04nxl9gLBy5/oCnNe4/LZ9PZYrcT7j4nHO85vc9e/Fq8nS6z3/PzfOK4As4DZr7ZvuOu2BGTg/opYD893X6Wdr7YAjfZ1EGrp636nfGBOK08RYYo8xpi3Ol9yZwHfA1zjJ0GfuF5m3v7nLfg7MBra6z3+BU1V/EOcD6C9AETAL6AX8xxgzsdy2xgI9cBKHHV7Pnw0k4tSCHAssxfnCWwH8Dnjaa9kubrwvAT/hfNDPquTQ73bXzwXOBW52X49+7vpnAik4X1Qtgcgavi4lr+2HOB/We4APcGpvPjHGnIiTnH3hLr7Vfb1+qCTWeJzE4yOcJGQfcAnwcCXLVspaWwjc5062wPmwLx9vuBvv8W5sOThfmlV5yuv/V93pNKADzjG/jVOe8cDdxpgJvsbs5VZjzJPu391urL1wvlgBHvJOxgBKvoyBDCATJxleZox53E1Qwsuv43oNGOQ2JV/rrj+nugDdpGa4O3k1zg+Lk9wvbaj8vfE5hxJy3OdK3jNdcJLhN3DOwY7AM8aYE9z9XYXTV/MYnCThU5z3Vfm4zsQpg0qTMVd159cr7usAzo+mpw5zPD+4758FOOf5PJz32BXAO8aY8k2yDwJzge8ricnblSXlj/PjoDxf3/P3Ab8Ac8qd679Syblew2O5F+ezoSlwozHm9GqO6ffu32KgPfCCMaapO28mzmdMGs45MK2abYkI9T8hew8nSZrtTn+E00dkEk6NwDqcJGgrTi1XHyr+kr3eWnuZtfYaa+0z7joAM93msHCcpjKAM621f8T55Q9wQ7ltbQCOt9Ze7Vb1l1gPnMehL4hY4AycZilwkrMSF+IkNRk4H6AAfdxfnd7usdZeBjxTbhvX4NRIfGitPcVaeyVgcL4ka/K6AAzBubghEzjZWjvJ3V8ozuu2GOfDF2CdtfbGcscNgLV2Dc6XfApOf7Bf3VnDyy9bjc1e/7euZP5QnIQ4EzjVvbjgk6o2WK7J8373GNbhJAtPAKk4yUBJ02BNYwanVmOq+/fHSuLfBGCMucYY4/H66+o2TV3pxnAMTo3ue8B6Y8yxlezr30Ahzg+Ns3CSyUwfYpyIU+OW7PbD/B9ODeolAJW9N6y1M3FqYnGXudH9Swcexakl2YGT2Ka62ys5z6a6j7daa8dbay/F+eHirSfwvhv/4ZKxas8va+39HOoz+IwbY2XHMw8nqYl0t7ETWI3TxHwazvvI23hr7ZXW2jsqi8vLCA6V/9hK5vv6nv+btXaCtXY8h871DJxz/UKcH0zeanIsY90y+M6dHkjV0nGazc/H+QxuAvQ2xnTkUM3jWe5nxr+q2ZaIUP+bLD/G+VAt6dQ/z1rr8fpV39f989az3PT/qtlHybZyrLUlCcFq97FLuWUXuzU55a124yppnttprT1gjCn51R4LpbUmPwFxlWyjFU6zWYll7mPJNkvW6eY+ltZUWWuL3O2XHIsvrwscOvbUkk7iHP7YD8utSZxZyaxWvm6jkn1W1k+wg/voHe8qYGQN9wPOBQqV9b+qacwAAytpsvSOvxPO67oC58vrGu8FrbWzjDEf4nzRnQxchdN0fhcVj20bTs3JGHf6eWCyDzGWNFe+7z6+5+7rUpyaoJr6CCchLK/k9avsPC3fL6qkPD/nUKJSQS2eX3DonD/e/fPWE6f5v0R1nx0lKuvUjztdk/e89/5KXps0r5rSNeXW7+o++nIsh/s8OZwUa20ugDEmC6dmLc4rLu/Py1XVbEtEqP81ZC9ba2+y1j5grZ1b0r+GQ30p3rPWhpT84XSCfrncNvKq2UfJtmKMMZ3d/0t+XW4ut+zhtlVUzXSJ83E+1JbjNFG18ZpXvomhJPErfyVfSZ+Q0g9gY0yo20SxyX3Kl9cFr+U7GWNKOnsf7tircpH7+AJO7V3JtM9X5blNNCX9t9Kp/MuwpAmqozEmxv2/TyXLlVfsPnq/H0pinIRTc/S8O10rVxJaa9dyKLm91RgTaa39HqdvYCljTIQx5iRrba619jNr7Z04ffrAaaqrTEms31kfhnYwxvTlUI3IX92+YI+7032MMUPc/0vOW+/XqfRcdpu4McY051Aydoq7/Fx3uuT1q+w8Lf8DcRlO0jAap7bycI70/KrseDa5j0+Ue4/0sOWGv7HWVvfZ4YuavOe99+d9rpe8N3uXW36T++jLsRzu8+RwvH94eq9TEleMW1sGvr0HRRq9+l5Ddjhv4jQrXmCM+Qzng6kHTg1DLyrp/Ho41tpdxpjZwDjgC2PM/3CaGOBQc2Ft2ek+9sbp03IkHWD/hVMjMsrtiL0Wp4P1CdT8dVkK/IjzpfmtMeZXnKYtD/Acvis5rvNwOsufV4N1rzTGjMTpr9Ib54vgmsP0n/oBp8a0J/C1e5GGL7VjqTi1b88YY9bgDEOxE6eD+BScPnoX1CBmX/0Jp/P5mcBKY0xJHx5vUTivfQpOgpLtFcsXVG4BTpP4xsPML2+S+7gDp7xLDMGp8ZiEcy6kus9PNcb0x+k/loLTET0SmGmM2YzT+TwTJ9G4F6e5vHyfpKdwLhh41O2PmIPTF+lMr2UO4tTQ/eDuc7e1trLauiM9vyo7nhdxaiCnGGO64TS39gVOxD8/YI/0Pf8DTheJ7sBCY8xGKp6jdX0sWGvTjDElF0x8boxZyqEEWUSqUN9ryCplrd2G84HwMc4H3KU4XyzP4nwo1dQfcX6hR+J8uGzAGbuosmaS32IWTk1VEc4X6kNVL16RWyMyDOfKpn44/ZcOAPk1fV2stcU4Cc2rOH2eLsBJCkZaa78rv3wV7sNppmmF08H4bzVY93yc1zwK5/X5vXWHvKgk3kJgFE5ScTROU3BJzV9VtRn/h9MB+Rycfj4xOEntanc78Ti1L7XKWvsNcBxOp/dmwB9wmgm/cePYjnPRxhNu/OfhJEf7ccYWe+Qw2/VYaxdYa6sdQ8+tOb3YnfyrtXZ0yR9OYgowwa29egyn6fAoN75e1tp8nNdvN045/dlterwMp5/iUDfekn6eJTH+2z3eFe5xJVHJmH/W2jR3/kHgAWNMZc3IR3p+VXY8P+O8977Bqd2bgFP+NX4v+uiI3vNe5/pinPd5M8qdowE4lhKX4PxY6ILzg6+kdrM2ahRFGqwQj8fXGmqR4GeMaWatPeA1/RlO89kD1tq7AheZSONQyXvwBZz+mG+4nfxFpBINtclSGq97jTE9cJrYBuAkY1k4Qx+IiP9dYYwZhTPWWzecmvhinJp4ETkMJWTS0PyM08x6Nk7n/0+Bu6y1vvanEpHfxgJtcZqys4BvcZrDKxujUERcarIUERERCbAG2alfREREpD5RQiYiIiISYPWuD9ny5cs9UVEVbrtYq/Ly8vD3PqTmVC7BR2USnFQuwUdlEpzqolyys7P3DB48uNo7h9S7hCwqKoq+fcvf9ad2paSk+H0fUnMql+CjMglOKpfgozIJTnVRLsnJyT7d2UZNliIiIiIBpoRMREREJMCUkImIiIgEmBIyERERkQBTQiYiIiISYErIRERERAJMCZmIiIhIgCkhExEREQkwJWQiIiIiAVbvRuq31nLttdeWee7CCy/kuuuuIzs7m/POO6/COpdffjmXX345e/bsYdy4cRXmX3vttVx00UWkpqYyadIksrOziY2NLZ1/yy23kJSUhLWWP/3pTxXWv/POOznjjDNYvnw5N954Y4X5f/vb3zjxxBP5/vvvuf322yvMf/LJJxkwYADz58/ngQceqDD/hRdewBjDRx99xGOPPVZh/uuvv06nTp3473//y/PPP19h/uzZs2nZsiUzZsxgxowZFeZ/+umnxMbG8txzzzFr1qwK87/++msA/vGPf/Dxxx+XmRcTE8PcuXMB+Otf/8qCBQvKzE9MTOTdd98FYPr06SxatKjM/I4dO/LGG28AcOONN7J8+fIy83v37s2LL74IwD333MOuXbvKzB8wYABPPvkkAJdeeilpaWll5p9wwgk89NBDAIwdO5a9e/eWmX/66adz1113AXDuueeSk5NTZv6IESP4y1/+AsCwYcMor7bPvfKC/dy7++676du3b4M/966++mrWrFlTZn4wn3vZ2dlcd911DfrcC4bPPY/Hw5333MeCBQsoLPZQWOShoKiY6LhmTLz9KdKz85n36uOk2Z8pLCwiIjyMsNAQmrdqy4RbHyU+OpxPXnyIbRtWExYaQlhoCOGhIfTo2YunnnmeuOhwbrr+WtauXVtm/8F87kH9+ty7/fbby3zfQ+2fe5VtozL1LiETERHxp+z8Ij7/dQf7svNZtH4vW9KzKSwqpsBNujxhOQz+6xfszylg77fryE3dX2b9sMxQnvt6HQmxkaRn5ePxQGhICEUeD/kFxeQfzGPW0lQy8wpJ35hO/u7MMuvbnO38+JDzAyN9SSpF+9MJDw0tTdp2RexgylvLaN88hk17ssjKKSA6PIzI8FBCQursZZJaFuLxeAIdQ42kpKR4dC/LxknlEnxUJsFJ5eK73IIilqfuJ3nzPpZsSid58z4ycgvLLBMZFkpCkwgSYiNpHhtBiyaRNI+NJCHWeS4hNpKEJhE0j42khTsdHx1OaOih7KiyMikq9pCVX0hGbiGZuYVk5BaQkVd2OtOdzig3fSCngO0HcigoOvQdHhYaQvvm0XRuEUunhFg6tYils9df89gIQpSxlVFH97JMHjx48JDqllMNmYiINBp7MvNYumkfyZvTWbJpH79uO1Ca1PRuE8eI/u05tmsCvVrHlyZhsZFhfklkwkJDaBodQdPoiCNav6jYw46DuWzZm01qejap+7LZku78zU/ZyZ7M/DLLx0eF06lFLJ1axJQmaSVJW4eEGKLCw2rjsOQIKSETEZEGyePxsGFPFsmbDtV+bdiTBUBkeCjHdGzG5JO7c2zXBAZ1TqB5bGSAI66ZsNAQOjSPoUPzGE7okVhhflZeIWn7ckqTtFT3ccPuLL62u8krLC5dNiQE2jaNrlCr1qlFDJ1axNIqLkq1a36mhExERBqE/MJiVm47wNJN6W4t2D72Zjm1RAmxEQzu0oKLju3EkK4J9OvQrMHXCDWJCse0jce0ja8wr7jYw57MvNJkzUnYckhNz+a7tXvYcTC3zPIxEWGlNWsdE7yStkSneTQmsmG/lnVBCZmIiNRLHo+HX7cd5LNfd/DjxnR+Tt1fWuvTNTGW0/q0ZkiXBIZ0bUGPVk1Uw+MlNDSE1k2jad00miFdW1SYn1tQRNq+nNJatVSvxG3R+r1k5ReVWb5lXBSdK2kK7ZLYhNbxUWX600nllJCJiEi94fF4WJ66n7krd/DpL9tJ25dDWGgI/do35dKhXZzmxy4JtI6PDnSo9Vp0RBg9W8fRs3VchXkej4f0rPzSBC1tXw5b9jr/L9m0jw9/3kaxx3tboaXJWZcWsXRp6Tx2TWxC++bRhIdpSFRQQiYiIkGuuNhD8pZ9zP1lB/NWbmfbgVwiwkL4fc+WTBneizOPakNCk/rV/6s+CwkJITEuisS4KAZ2TqgwP7+wmG37c9icns2WvVls3pvNpr3ZbN6bxTdryvZdCw8NoWNCDJ0Tm9A18VCtWtdEp5YtOqLxNIUqIRMRkaBTVOxh8cZ05q7czryVO9iVkUdkeCin9GrFX842nN63Dc1ijuzqRPGvyPBQurZsQteWTYBWZeYVF3vYlZHHpr1ZbNmbzaa9WWxOd5K1ZVsqDjnSrpkzjEfXxCZ0aRlL95ZN6NYyji6JDS9ZU0ImIiJBobjYw+7MPNL25bBtfw55hUUM7NScc/u1pUNCDO2axRBRT5u32rVrF+gQgkJoaAhtm0XTtlk0Q7uXvTLU4/GQX1hMZl4hWfmFZOYWOf/nFZKZV0heoTP9y9b9/LJ1P7GR4cRHhxMfFU58dARx0c50TIR/hinxNyVkIiISMEXFHrakZ7NuVwbrd2eRW1BERFgo3Vo24ZiOzenaskm9TcK8FRQUBDqEoBcSEkJURBhREWEkElVhfn5hMfuy852/rAL2ZeeTmp7NvuwCCoq8m0FDaR4bQUKTioP3BvOVtUrIRESkThUWFbM5PZt1OzNZvyeT/MJiIsNC6d4qjl6tneYodfSW8iLDQ2nTNJo2TctesOHxeMjKK6qQrO06mMu6nRl4348oNjK8NEnrnBhLbkExwUIJmYiI1ImComKWbtrHsi37yC8qJio8jJ6t4ujVJo5OLWIJD1USJjUXEhJCXHQ4cdHOnQi8FRYXczCngHQ3SdvvJmzrd2eyPyefjD05DOwfoMDLUUImIiJ+5fF4WLsrk2/X7CYjr5BerePp16EpHRNiCdP4VOJH4aGhtGgSRYsmFZtAi4qLWWMzK1krMPRzREREfNa3b19GjRrFiBEjmDJlCjk5OVUuvyczj3d/SuPTX7YTFRHGuMEdOb9/O64Yn8SB/fuqXDcrK4u7776bM844gzFjxjBp0iR+/vlnAAYOHFhrx/TWW2/x/vvvA7B+/XpGjRrF6NGj2bJlCxMmTDiibc6fP59169aVTr/00kt8//33tRIvwIMPPsjJJ59McXHwNLnVxKpVq7j99tsB57UZNWpU6XnVt29f9u/fD8DBgweZMmUK55xzDueeey7Lli0D4NFHHyUpKYnbbrutdJsffPABM2bMKJ221jJt2rTDxhAWZDWyqiETERGfRUdH88EHHwBwyy238Pbbb3PFFVdUWC63oIhF6/eyIm0/URFhDO/Tmn4dmhFag6vf7rzzTjp27Mjnn39OaGgoqamprF+/vtaOpcTEiRNL/1+wYAFnn3021113HQBvv/32EW1z/vz5DBs2jJ49ewIwefJkWrVqVc1avikuLmb+/Pm0a9eOxYsXM3To0FrZbnkejwePx0OoHxKXf/3rX6Wv8eTJk5k8eTIAX375JTNmzKB58+bAocTz6aefJj8/n9zcXDIyMli1ahUfffQRd9xxB9ZaunTpwpw5c3jppZdK92GMYceOHWzbto327dvX+jHUtuBKD0VEpN4YMmQImzdvBpzaiXHjxjFq1Cj+fPP/8cp361mRtp+VH73EZ0/eyvQ/XcIz//xnhW3k5uYyefJkZs2aVeb5LVu28PPPP3PjjTeWJgSdOnVi2LBhZZbLysrisssu44ILLiApKYn58+cDkJ2dzdVXX83IkSMZMWIEn376KQD/+Mc/OO+880hKSuLvf/87AP/85z95+eWXWbhwIa+99hpvvfUWkyZNAsrWxL344oskJSUxcuRI/vGPfwAwa9Ysxo4dy8iRI7nhhhvIycnhp59+4ssvv+SRRx5h1KhRbNmyhQcffJB58+YBsGjRIkaPHk1SUhLTp08nP9+53+bw4cN5+umnS4/lcMnnjz/+SM+ePZk4cSKffPJJmddi+vTpJCUlkZSUxGeffQbAN998wwUXXMDIkSO57LLLyhxziREjRpCWlkZaWhpnn302t912GyNGjGD79u3cc889jBkzhvPPP5+nn366dJ0VK1YwYcIERo4cybhx48jMzOSSSy4hJSWldJmJEyeyevXqMvFnZmZiraVPnz4Vju2TTz5hxIgRAGRkZLBkyRLGjRsHQGRkJE2bNiUkJITCwkI8Hg+5ubmEh4fz8ssvM2nSJCIiyo5Nd9ppp5V5jYKZashERKTGCgsL+eabbzj55JNZv349c+fO5bHnX+Hb9fuY89ITNF/+LTdOvpSIIbfTvHlzioqKuPzyy1m9enXpF3F2djY333wzo0ePZvTo0WW2v3btWvr27UtYWNXDFERFRfHss88SFxdHeno6F110EaeffjrffvstrVu35sUXXwScL/d9+/bxxRdfMG/ePEJCQjh48GCZbZ166qlMmDCB2NhYrrzyyjLzFi5cyJdffsmsWbOIiYkpbVI788wzufDCCwF44oknmD17NpMmTWL48OEMGzaMc845p8x28vLymDZtGjNmzKBbt27cdtttzJw5k8svvxyAhIQE3nvvPd58801eeeUVHnzwwQrH/Mknn3D++edzxhln8Pjjj1NQUEBERATPPfcccXFxfPTRRwAcOHCA9PR07rrrLt544w06depUGndVNm/ezN///ncGDBgAwE033VShDLt3785NN93EE088Qf/+/cnMzCQ6Oppx48YxZ84c7rjjDjZu3EheXl6FxGvlypX07t27wn5zcnL49ttvueuuuwBIS0ujRYsWTJ8+ndWrV/O73/2OO+64g7i4OE455RRGjx7NCSecQHx8PCtWrODPf/5zhW3269ePf//731x11VXVHnegqYZMRER8lpuby6hRoxg7dizt27dn3LhxfPXNdyQvX8HEiy7khTuvYf+mX2kTlkWr+Cjmzp3LBRdcwOjRo1m7dm2ZWp/rrruOMWPGVEjGasLj8fD444+TlJTEFVdcwc6dO9mzZw+9e/fm+++/59FHH2Xp0qXEx8cTHx9PVFQUt99+O59//jnR0b7f73LRokWMGTOGmJgYgNImtbVr13LxxReTlJTERx99xNq1a6vczsaNG+nYsSPdunUD4IILLmDp0qWl88866yzASSS2bt1aYf38/HwWLlzIGWecQVxcHMcccwzfffddaYyXXHJJ6bLNmjVj+fLlDBkyhE6dOpWJuyrt27cvTcaASstw48aNtGrViv79nUsU4+LiCA8P55xzzuHrr7+moKCAd999lzFjxlTY/u7du0lIqHjLpa+++opBgwaVxlhYWMiqVauYOHEi77//PjExMaUJ9lVXXcUHH3zAtGnTeOqpp5gyZQrvvPMOU6dO5bnnnivdZmJiIrt27ar2mIOBashERMRn3n3ICouK+WnLPn7csJeex53GlKk3M6RrQulArqmpqbzyyivMnj2bZs2aMW3aNPLy8kq3NWjQIL799luSkpIqjKzeq1cvVq9eTVFRUZW1ZB999BHp6enMmTOHiIgIhg8fTl5eHt26dWPOnDksXLiQJ598kqFDh3L99dcze/ZsFi1axLx583jjjTf4z3/+85tej2nTpvHcc8/Rp08f5syZw+LFi3/T9kqa3EJDQykqKqow/7vvviMjI4ORI0cCTq1SVFQUp512Wo32ExYWVuaCAO9yiY09NHREdWVYXkxMDCeeeCILFixg7ty5zJkzp8Iy0dHRpc203kpq/kq0bduWtm3bcswxxwBwzjnnlCZkJVatWoXH46Fbt248/vjjvPzyy0yfPp1NmzbRtWtX8vLyiIqqeIVlMFINmYiI1IjH42H9rkz+88Nmvl+/l+OHDmX3qsX0bg4RYaHs37+frVu3kpWVRUxMDPHx8ezZs4dvvvmmzHamTJlCs2bNuO+++yrso3PnzvTr14+nn34aj8cZ2jMtLY2vv/66zHIZGRkkJiYSERHBDz/8UFqrtHPnTmJiYhg1ahRXXnklq1atIisri4yMDE499VRuv/12rLU+H/OJJ57InDlzSq8qLWn6y8rKolWrVhQUFJQ2FQK/8RsdAAAgAElEQVQ0adKErKysCtvp1q0bW7duLdP37thjj/U5jk8++YQHHniAL7/8ki+//JIFCxbw/fffk5OTw4knnsibb75ZuuyBAwcYMGAAS5cuJTU1tUzcHTp0YNWqVQD8+uuvpKWlVbq/w5Vht27d2L17NytWrACcfmGFhc59KMePH88DDzzA0UcfTbNmzSpss3v37qXHX6Kkv9jpp59e+lyrVq1o27YtGzZsAJwawB49epRZ76mnnmLq1KkUFhaWJrAhISHk5uYCsGnTJnr16lXt6xoMVEMmIiI+83g8vLdsK1vSs0lsEsmYQR3p3KI37UNu4o9//CPFxcVERERw9913M2DAAI466ijOPfdc2rZty6BBgyps74477uD222/nkUceKTOEAThX2D388MOceeaZREdHk5CQwK233lpmmaSkJK699lqSkpLo168f3bt3B2DNmjU88sgjhIaGEh4ezr333ktWVhbXXXddaQ1PVUMilHfKKaewevVqxo4dS0REBKeeeio333wzU6dOZfz48bRo0YJjjjmmNAk777zzuOuuu3j99dfLdISPiorioYceYurUqRQVFdGvX78yV3lWpaSPlXcCGxsby+DBg/nqq6+49tpruf/++xkxYgShoaFcf/31nHXWWdx///3ccMMNFBcXk5iYyKuvvsrZZ5/NBx98wPnnn0///v3p2rVrpfvs06dPpWUYGRnJE088wQMPPEBubi7R0dG8+uqrhIeH069fP+Li4iptrgTo0aMHmZmZZGZmEhcXB8AXX3zB73//+zK1cwB33XUXf/nLXygoKKBTp0489NBDpfPmz59Pv379aNOmDeAMyZKUlETv3r1L+639+OOPFS4ECVYhJb88/MEY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Ac4Cnt7H9xaRNKNTliJSl/QC5uytkXOuK7AwEaZqtc9ujKbG7W2cc79yzi10zr0PuG/YrzGwObH8cuJ1RES+kUbIRKQu6Q781Tm38zZB95vZw7tpN4L46cZ92ecrifvbHWRmSxPr/Ynf764P8ePmbKCoxi4NnHNzgBzgQGBoYvunwKG1/+eJSLpSIBOROsE51xZYb2a9atF8GPDDfdynpnxgS431wcBLZlaWqGXXGxHXPGV5OPCEc66HmUWdc5XOuTwz276PNYhIGlEgE5G6oidQvOvGROi6GdhKfFRsBtDUzFYnbiC8u30KEm3fIH768XQzi9Vo8iXx0a59Zmb/ds7lAwcA64BsoPzbvJaIpA/NIRORuqIX8NlutncBKoF7zext4Bjgnb3scyjwrJndQDw0taj5pJltBiLOuZ2hbBpwinOugXMuDzhpT0U657oAEWCjc64FsMHMqmr5bxSRNKURMhGpK3oCRzvnRiTWA2Cwmb3lnFsB3Oecu4L4/LFJ37QP8UA2I7GtiZmt3837vQkcBbxtZrOdcxOBT4gHuJm7tN05hwzil764IHG68hjgte/wbxaRNBEKgsB3DSIi35pz7g7iI1I5wNXAh8CgbxqVcs49C6wGGgKTzGzKbtr0A642s/O+Q20vAteb2cJv+xoikh4UyEQk7TjnnqxN0HLOXQQ8Xstrke26bxYwysye+DY1ikh6USATERER8UyT+kVEREQ8UyATERER8UyBTERERMQzBTIRERERzxTIRERERDxTIBMRERHxTIFMRERExDMFMhERERHPFMhEREREPPs/dJvU21y07AoAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 720x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Ensure that the model is in \"evaluation\" mode\n",
    "# -- Therefore batch normalization is not computed and dropout is not performed\n",
    "# -- Note: This is the cause of a lot of bugs\n",
    "model.eval()\n",
    "\n",
    "acc_vs_spr = list()\n",
    "sprs = list()\n",
    "\n",
    "for spr in np.linspace(50.0, 0.0, num=26):\n",
    "    right = 0\n",
    "    total = 0\n",
    "    \n",
    "    for x, y in dl:\n",
    "        adv_x = fgsm(x, y, spr=spr, input_size=input_samples, sps=8, net=model)\n",
    "\n",
    "        predictions = model.predict(adv_x)\n",
    "        right += (predictions == y).sum().item()\n",
    "        total += len(y)\n",
    "\n",
    "    acc = float(right) / total\n",
    "    acc_vs_spr.append(acc)\n",
    "    sprs.append(spr)\n",
    "\n",
    "fig = plot_acc_vs_spr(acc_vs_spr=acc_vs_spr,\n",
    "                      spr=sprs,\n",
    "                      title=\"Performance of a Digital FGSM Attack after Hardening\"\n",
    "                     )\n",
    "if fig_dir is not None:\n",
    "    file_path = \"{fig_dir}/hardened_direct_access_fgsm.pdf\".format(fig_dir=fig_dir)\n",
    "    print(\"Saving Figure -> {file_path}\".format(file_path=file_path))\n",
    "    fig.savefig(file_path, format=\"pdf\", transparent=True)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
